package controllers;

import java.text.NumberFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import repository.AuctionRepository;
import repository.PurchaseRepository;
import repository.impl.IncomeReport;
import validator.ConfirmationFormValidator;
import validator.ReportValidator;

import command.ConfirmationForm;
import command.ReportForm;

import domain.Auction;
import domain.Confirmation;
import domain.Confirmation.Confirmated;
import domain.Item;
import domain.Offer;
import domain.Purchase;
import domain.exceptions.BigRangeException;

@Controller
public class PurchaseController {
	private PurchaseRepository purchaseRepository;
	private ConfirmationFormValidator confirmationFormValidator;
	private ReportValidator reportValidator;
	private AuctionRepository auctionRepository;
	
	@Autowired
	public PurchaseController(PurchaseRepository purchaseRepository, ConfirmationFormValidator confirmationFormValidator,
			ReportValidator reportValidator, AuctionRepository auctionRepository){
		this.purchaseRepository = purchaseRepository;
		this.confirmationFormValidator = confirmationFormValidator;
		this.reportValidator = reportValidator;
		this.auctionRepository=auctionRepository;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView conflictPurchases() {
		ModelAndView mav = new ModelAndView();
		List<Purchase> conflicted = purchaseRepository.getConflictedPurchases();
		mav.addObject("conflicted", conflicted);
		mav.setViewName("purchase/conflictPurchasesList");
		return mav;
	}
	
	//buyer
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView confirmationBuyer(@RequestParam("purchaseId") Purchase purchase){
		ModelAndView mav = new ModelAndView();
		ConfirmationForm form = new ConfirmationForm();
		form.setBuyerConfirmation(purchase.getConfirmation());
		mav.addObject("purchase", purchase);
		mav.addObject("confirmationForm", form);
		mav.setViewName("purchase/confirmationBuyer");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.POST)
	protected ModelAndView confirmItemBuyer(@RequestParam("purchaseId") Purchase purchase, 
			ConfirmationForm confirmationForm, Errors errors){

		ModelAndView mav = new ModelAndView();
		confirmationFormValidator.validate(confirmationForm, errors);
		if(errors.hasErrors()){
			mav.addObject("purchase", purchase);
			mav.setViewName("purchase/confirmationBuyer");
			return mav;
		}
		
		Confirmation confirmation = purchase.getConfirmation();
		confirmation.setBuyerConfirmation(confirmationForm.getConfirmation());
		confirmation.setComment(confirmationForm.getComment());
		confirmation.setCalification(confirmationForm.getCalification());
		
		if (confirmation.succesful()) {
			purchase.setDebtPending(true);
		} else if (confirmation.fail()) {
			//Transaccion cancelada, recupera stock
			purchase.getItem().addStock(purchase.getQty());
		}
		
		if(confirmation.hasFinish()){
			purchase.getItem().getUser().recieveQualification(confirmation.getPoints());
		}
		
		mav.setViewName("redirect:../user/operationHistory?opcode=0");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView confirmationSeller(@RequestParam("purchaseId") Purchase purchase){
		ModelAndView mav = new ModelAndView();
		ConfirmationForm form = new ConfirmationForm();
		form.setSellerConfirmation(purchase.getConfirmation());
		mav.addObject("purchase", purchase);
		mav.addObject("confirmationForm", form);
		mav.addObject("commission", purchase.calcCommission());
		mav.setViewName("purchase/confirmationSeller");
		return mav;
	}
	

	@RequestMapping(method = RequestMethod.POST)
	protected ModelAndView confirmItemSeller(@RequestParam("purchaseId") Purchase purchase, 
			ConfirmationForm confirmationForm, Errors errors){

		ModelAndView mav = new ModelAndView();
		if(confirmationForm.getConfirmation()==null){
			errors.rejectValue("confirmation", "empty");
		}
		if(errors.hasErrors()){
			mav.addObject("purchase", purchase);
			mav.setViewName("purchase/confirmationSeller");
			return mav;
		}

		Confirmation confirmation = purchase.getConfirmation();
		confirmation.setSellerConfirmation(confirmationForm.getConfirmation());
		
		if (confirmation.succesful()) {
			purchase.setDebtPending(true);
		} else if (confirmation.fail()) {
			//Transaccion cancelada, recupera stock
			purchase.getItem().addStock(purchase.getQty());
		}
		
		if(confirmation.hasFinish()){
			purchase.getItem().getUser().recieveQualification(confirmation.getPoints());
		}

		mav.setViewName("redirect:../user/operationHistory?opcode=1");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView pendingDebts() throws ParseException {
		ModelAndView mav = new ModelAndView();
		List<Purchase> pending = purchaseRepository.getDebtPendingPurchases();
		
		if (!pending.isEmpty()) {
			List<String> debts = new ArrayList<String>();
			for (Purchase p : pending) {
				double debt = p.calcCommission();
				NumberFormat twoDForm =  NumberFormat.getInstance(Locale.getDefault());
				twoDForm.setMinimumFractionDigits(2);
				twoDForm.setMaximumFractionDigits(2);
				String num = twoDForm.format(debt);
				debts.add(num);
			}
			mav.addObject("purchases", pending);
			mav.addObject("debts", debts);
			mav.addObject("canConfirmDebt", true);
		}
		mav.setViewName("/admin/pendingDebts");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET) 
	protected ModelAndView cancelDebt(@RequestParam("purchaseId") Purchase purchase) throws ParseException {
		purchase.setDebtPending(false);
		return pendingDebts();
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView incomeReport() {
		ModelAndView mav = new ModelAndView();
		mav.addObject("reportForm", new ReportForm());
		mav.addObject("action", "../purchase/incomeReport");
		mav.setViewName("admin/incomeReport");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.POST)
	protected ModelAndView incomeReport(ReportForm reportForm, Errors errors) throws  ParseException{
		reportValidator.validate(reportForm, errors);
		ModelAndView mav = new ModelAndView();
		if(errors.hasErrors()){
			mav.setViewName("admin/incomeReport");
			return mav;
		}
		
		try {
			List<IncomeReport> report = purchaseRepository.getIncomeReport(reportForm.getBefore(), reportForm.getAfter());
			mav.addObject("incomes", report);
		}catch(BigRangeException e){
			errors.rejectValue("before", "bigyearrange");
		}
		mav.setViewName("admin/incomeReport");
		return mav;
		
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView pendingConfirmationReport(){
		ModelAndView mav = new ModelAndView();
		List<Purchase> list = purchaseRepository.getPendingConfirmationPurchases(15);
		mav.addObject("purchases", list);
		mav.setViewName("admin/pendingConfirmations");
		return mav;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView cancelPurchase(@RequestParam("purchaseid") Purchase purchase){
		Item item = purchase.getItem();
		if(item.getType().equals(Item.Type.auction)){
			Auction auction = auctionRepository.getAuction(item);
			Offer offer = auction.getMaxOffer();
			purchaseRepository.deletePurchase(purchase);
			auction.deleteOffer(offer);
			auction.restartAuction();
		}
		item.addStock(purchase.getQty());
		purchase.cancelPurchase();
		return pendingConfirmationReport();
	}
	
	@RequestMapping(method = RequestMethod.GET)
	protected ModelAndView resolvePurchase(@RequestParam("purchaseId") Purchase purchase, @RequestParam("confirmType") int confirmType) {
		
		Confirmation c = purchase.getConfirmation();
		
		if (confirmType == 0) {
			c.setBuyerConfirmation(Confirmated.realize);
			c.setSellerConfirmation(Confirmated.realize);
		} else {
			c.setBuyerConfirmation(Confirmated.dontrealize);
			c.setSellerConfirmation(Confirmated.dontrealize);
		}
		
		// lo da como exitoso, ahora es moroso por esa venta
		if (c.succesful()) {
			purchase.setDebtPending(true);
		}
		// Si da la compra como denunciada, recupera stock
		if (c.fail()) {
			purchase.getItem().addStock(purchase.getQty());
		}
		
		return conflictPurchases();
	}
	
}
